package com.yds.ydsdatasetbackend.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yds.ydsdatasetbackend.exception.BusinessException;
import com.yds.ydsdatasetbackend.exception.ErrorCode;
import com.yds.ydsdatasetbackend.exception.ThrowUtils;
import com.yds.ydsdatasetbackend.manager.rabbitmq.train.MyFileTrainProducer;
import com.yds.ydsdatasetbackend.model.dto.file.train.FileTrainAddRequest;
import com.yds.ydsdatasetbackend.model.dto.file.train.FileTrainEditRequest;
import com.yds.ydsdatasetbackend.model.dto.file.train.FileTrainQueryRequest;
import com.yds.ydsdatasetbackend.model.entity.File;
import com.yds.ydsdatasetbackend.model.entity.FilePredict;
import com.yds.ydsdatasetbackend.model.entity.FileTrain;
import com.yds.ydsdatasetbackend.model.entity.User;
import com.yds.ydsdatasetbackend.model.enums.FileModelEnum;
import com.yds.ydsdatasetbackend.model.enums.FileTrainEnum;
import com.yds.ydsdatasetbackend.model.vo.FileTrainVO;
import com.yds.ydsdatasetbackend.model.vo.FileVO;
import com.yds.ydsdatasetbackend.model.vo.UserVO;
import com.yds.ydsdatasetbackend.service.FilePredictService;
import com.yds.ydsdatasetbackend.service.FileService;
import com.yds.ydsdatasetbackend.service.FileTrainService;
import com.yds.ydsdatasetbackend.mapper.FileTrainMapper;
import com.yds.ydsdatasetbackend.service.UserService;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author YDS
 * @description 针对表【file_train(文件训练)】的数据库操作Service实现
 * @createDate 2025-02-05 14:56:52
 */
@Service
public class FileTrainServiceImpl extends ServiceImpl<FileTrainMapper, FileTrain>
        implements FileTrainService {

    @Resource
    private FileService fileService;

    @Resource
    private UserService userService;

    @Resource
    MyFileTrainProducer myFileTrainProducer;

    @Resource
    private FilePredictService filePredictService;

    @Override
    public FileTrainVO addFileTrain(FileTrainAddRequest fileTrainAddRequest, User loginUser) {
        // 校验参数
        // 文件id不能乱填，或是为空
        Long fileId = fileTrainAddRequest.getFileId();
        if (fileId == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        File file = fileService.getById(fileId);
        ThrowUtils.throwIf(file == null, ErrorCode.NOT_FOUND_ERROR, "文件不存在");
        ThrowUtils.throwIf(fileTrainAddRequest.getTrainRate() <= 10 || fileTrainAddRequest.getTrainRate() >= 90, ErrorCode.PARAMS_ERROR, "文件训练比例参数不合法");
        ThrowUtils.throwIf(fileTrainAddRequest.getIsRefresh() != 0 && fileTrainAddRequest.getIsRefresh() != 1, ErrorCode.PARAMS_ERROR);
        List<String> modelList = FileModelEnum.getValues();
        ThrowUtils.throwIf(!modelList.contains(fileTrainAddRequest.getModel()), ErrorCode.PARAMS_ERROR,"此模型不存在");
        List<Long> selectFeatures = fileTrainAddRequest.getSelectFeatures();
        Collections.sort(selectFeatures);
        List<Long> selectTargets = fileTrainAddRequest.getSelectTargets();
        Collections.sort(selectTargets);
        if(selectFeatures.isEmpty()) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"特征字段为空");
        }
        if(selectTargets.isEmpty()) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"目标字段为空");
        }


        // 填写参数，并提交数据库
        FileTrain fileTrain = new FileTrain();
        fileTrain.setModel(fileTrainAddRequest.getModel());
        fileTrain.setTrainRate(fileTrainAddRequest.getTrainRate());
        fileTrain.setIsRefresh(fileTrainAddRequest.getIsRefresh());
        fileTrain.setIntroduction(fileTrainAddRequest.getIntroduction());
        fileTrain.setTrainStatus(FileTrainEnum.WAITING.getValue());
        fileTrain.setSelectFeatures(JSONUtil.toJsonStr(selectFeatures));
        fileTrain.setSelectTargets(JSONUtil.toJsonStr(selectTargets));
        fileTrain.setFileId(fileTrainAddRequest.getFileId());
        fileTrain.setUserId(loginUser.getId());

        boolean save = this.save(fileTrain);
        ThrowUtils.throwIf(!save, ErrorCode.OPERATION_ERROR, "训练文件创建失败");

        // 发送请求给rabbitmq,让它处理信息
        Long fileTrainId = fileTrain.getId();
        myFileTrainProducer.sendMessage("file_exchange","my_routingKey1", String.valueOf(fileTrainId));

        return this.getFileTrainVO(fileTrain, null);

    }

    @Override
    public void editFile(FileTrainEditRequest fileTrainEditRequest, User loginUser) {
        // 在此处将实体类和 DTO 进行转换
        FileTrain fileTrain = this.getById(fileTrainEditRequest.getId());
        ThrowUtils.throwIf(fileTrain == null, ErrorCode.NOT_FOUND_ERROR);
        // 校验权限
        checkFileTrainAuth(loginUser, fileTrain);
        // 更新
        fileTrain.setIntroduction(fileTrainEditRequest.getIntroduction());
        // 操作数据库
        boolean result = this.updateById(fileTrain);
        ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
    }

    @Override
    public void checkFileTrainAuth(User loginUser, FileTrain fileTrain) {
        Long loginUserId = loginUser.getId();
        if (!loginUserId.equals(fileTrain.getUserId()) && !userService.isAdmin(loginUser)) {
            throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
        }
    }

    @Override
    public FileTrainVO getFileTrainVO(FileTrain fileTrain, HttpServletRequest request) {
        // 对象转封装类
        FileTrainVO fileTrainVO = FileTrainVO.objToVo(fileTrain);
        // 关联查询用户信息
        Long userId = fileTrainVO.getUserId();
        if (userId != null && userId > 0) {
            User user = userService.getById(userId);
            UserVO userVO = userService.getUserVO(user);
            fileTrainVO.setUser(userVO);
        }
        Long fileId = fileTrain.getFileId();
        if (fileId != null && fileId > 0) {
            File file = fileService.getById(fileId);
            FileVO fileVO = fileService.getFileVO(file, request);
            fileTrainVO.setFile(fileVO);
        }
        return fileTrainVO;
    }

    /**
     * 分页获取图片封装,将获取到的页进行脱敏
     */
    @Override
    public Page<FileTrainVO> getFileTrainVOPage(Page<FileTrain> fileTrainPage, HttpServletRequest request) {
        List<FileTrain> fileTrainList = fileTrainPage.getRecords();
        Page<FileTrainVO> fileTrainVOPage = new Page<>(fileTrainPage.getCurrent(), fileTrainPage.getSize(), fileTrainPage.getTotal());
        if (CollUtil.isEmpty(fileTrainList)) {
            return fileTrainVOPage;
        }
        // 对象列表 => 封装对象列表
        List<FileTrainVO> fileTrainVOList = fileTrainList.stream().map(FileTrainVO::objToVo).collect(Collectors.toList());
        // 1. 关联查询用户信息以及文件信息
        Set<Long> userIdSet = fileTrainList.stream().map(FileTrain::getUserId).collect(Collectors.toSet());
        Map<Long, List<User>> userIdUserListMap = userService.listByIds(userIdSet).stream()
                .collect(Collectors.groupingBy(User::getId));

        Set<Long> fileIdSet = fileTrainList.stream().map(FileTrain::getFileId).collect(Collectors.toSet());
        Map<Long, List<File>> fileIdFileListMap = fileService.listByIds(fileIdSet).stream()
                .collect(Collectors.groupingBy(File::getId));
        // 2. 填充信息
        fileTrainVOList.forEach(fileTrainVO -> {
            Long userId = fileTrainVO.getUserId();
            Long fileId = fileTrainVO.getFileId();
            User user = null;
            File file = null;
            if (userIdUserListMap.containsKey(userId)) {
                user = userIdUserListMap.get(userId).get(0);
            }
            if (fileIdFileListMap.containsKey(fileId)) {
                file = fileIdFileListMap.get(fileId).get(0);
            }
            fileTrainVO.setFile(fileService.getFileVO(file, request));
            fileTrainVO.setUser(userService.getUserVO(user));
        });
        fileTrainVOPage.setRecords(fileTrainVOList);
        return fileTrainVOPage;
    }

    /**
     * 分页获取图片包装
     *
     * @param fileTrainQueryRequest
     * @return
     */
    @Override
    public QueryWrapper<FileTrain> getQueryWrapper(FileTrainQueryRequest fileTrainQueryRequest) {
        QueryWrapper<FileTrain> queryWrapper = new QueryWrapper<>();
        if (fileTrainQueryRequest == null) {
            return queryWrapper;
        }
        // 从对象中取值
        Long id = fileTrainQueryRequest.getId();
        String model = fileTrainQueryRequest.getModel();
        String introduction = fileTrainQueryRequest.getIntroduction();
        String trainStatus = fileTrainQueryRequest.getTrainStatus();
        Long fileId = fileTrainQueryRequest.getFileId();
        Long userId = fileTrainQueryRequest.getUserId();
        String searchText = fileTrainQueryRequest.getSearchText();
        Date startCreateTime = fileTrainQueryRequest.getStartCreateTime();
        Date endCreateTime = fileTrainQueryRequest.getEndCreateTime();
        String sortField = fileTrainQueryRequest.getSortField();
        String sortOrder = fileTrainQueryRequest.getSortOrder();

        // 从多字段中搜索
        if (StrUtil.isNotBlank(searchText)) {
            // 需要拼接查询条件
            queryWrapper.and(qw -> qw.like("model", searchText)
                    .or()
                    .like("introduction", searchText)
            );
        }
        queryWrapper.eq(ObjUtil.isNotEmpty(id), "id", id);
        queryWrapper.eq(ObjUtil.isNotEmpty(userId), "userId", userId);
        queryWrapper.eq(ObjUtil.isNotEmpty(fileId), "fileId", fileId);
        queryWrapper.like(StrUtil.isNotBlank(introduction), "introduction", introduction);
        queryWrapper.like(StrUtil.isNotBlank(trainStatus), "trainStatus", trainStatus);
        queryWrapper.eq(StrUtil.isNotBlank(model), "model", model);
        queryWrapper.ge(ObjUtil.isNotEmpty(startCreateTime), "createTime", startCreateTime);
        queryWrapper.lt(ObjUtil.isNotEmpty(endCreateTime), "createTime", endCreateTime);
        // 排序
        queryWrapper.orderBy(StrUtil.isNotEmpty(sortField), sortOrder.equals("ascend"), sortField);
        return queryWrapper;
    }


    /**
     * 删除文件
     * @param fileTrainId
     * @param loginUser
     */
    @Override
    public void deleteFileTrain(long fileTrainId, User loginUser) {
        ThrowUtils.throwIf(fileTrainId <= 0, ErrorCode.PARAMS_ERROR);
        ThrowUtils.throwIf(loginUser == null, ErrorCode.NO_AUTH_ERROR);
        // 判断是否存在
        FileTrain fileTrain = this.getById(fileTrainId);
        ThrowUtils.throwIf(fileTrain == null, ErrorCode.NOT_FOUND_ERROR);
        // 校验权限
        checkFileTrainAuth(loginUser, fileTrain);

        List<Long> filePredictList = filePredictService.lambdaQuery()
                .eq(FilePredict::getTrainId, fileTrainId)
                .list().stream().map(FilePredict::getId).collect(Collectors.toList());

        // 删除文件对应的预测信息
        if(!filePredictList.isEmpty()) {
            boolean result = filePredictService.removeBatchByIds(filePredictList);
            ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
        }


        boolean result = this.removeById(fileTrainId);
        ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
    }

}




